import 'dart:convert';
import 'dart:typed_data';
import 'package:cryptography/cryptography.dart';

/// 与前端 JS 保持一致的 AES-GCM 解密工具
/// 数据格式：IV(12 bytes) + CIPHERTEXT(...) + TAG(16 bytes)
class AesGcmImageDecrypt {
  // 与 JS 默认 key 一致（32 字节 = 256 bit）
  static const String _defaultKey = '12345678901234567890123456789012';

  static final AesGcm _aes = AesGcm.with256bits();

  /// 解密图片字节；失败时返回原始字节，避免界面崩溃
  static Future<Uint8List> decryptBytes(
      Uint8List encryptedBytes, {
        String? key,
      }) async {
    try {
      // 1) 若已是明文图片（JPEG/PNG/GIF/WebP/BMP），直接返回
      if (_isPlainImage(encryptedBytes)) {
        return encryptedBytes;
      }

      // 2) 最小长度校验：IV(12) + TAG(16) + 至少1字节密文
      const ivLen = 12;
      const tagLen = 16;
      if (encryptedBytes.length < ivLen + tagLen + 1) {
        return encryptedBytes;
      }

      // 3) 切分：IV / CIPHERTEXT / TAG
      final iv = encryptedBytes.sublist(0, ivLen);
      final tag = encryptedBytes.sublist(encryptedBytes.length - tagLen);
      final ciphertext = encryptedBytes.sublist(ivLen, encryptedBytes.length - tagLen);

      // 4) 构造 SecretKey（**不要**再 base64 一次；JS 用的是原始 32 字节字符串）
      final keyStr = key ?? _defaultKey;
      if (keyStr.length != 32) {
        // 长度不对会直接失败；这里也可以选择 pad/truncate，但建议与前端保持严格一致
        throw StateError('AES-256 key 必须是 32 字符（32 字节）。当前长度: ${keyStr.length}');
      }
      final secretKey = SecretKey(utf8.encode(keyStr));

      // 5) 组装 SecretBox 并解密（AES-GCM 需要 MAC/tag）
      final box = SecretBox(
        ciphertext,
        nonce: iv,
        mac: Mac(tag),
      );

      final clear = await _aes.decrypt(
        box,
        secretKey: secretKey,
      );

      return Uint8List.fromList(clear);
    } catch (e) {
      // 失败容错：返回原始字节
      // ignore: avoid_print
      print('图片解密失败，返回原始数据: $e');
      return encryptedBytes;
    }
  }


  /// 简单的文件头嗅探：若本身是明文图片就直接用
  static bool _isPlainImage(Uint8List d) {
    if (d.length >= 2 && d[0] == 0xFF && d[1] == 0xD8) return true; // JPEG
    if (d.length >= 8 &&
        d[0] == 0x89 && d[1] == 0x50 && d[2] == 0x4E && d[3] == 0x47) return true; // PNG
    if (d.length >= 6 && d[0] == 0x47 && d[1] == 0x49 && d[2] == 0x46) return true; // GIF
    if (d.length >= 12 &&
        d[0] == 0x52 && d[1] == 0x49 && d[2] == 0x46 && d[3] == 0x46 &&
        d[8] == 0x57 && d[9] == 0x45 && d[10] == 0x42 && d[11] == 0x50) return true; // WebP
    if (d.length >= 2 && d[0] == 0x42 && d[1] == 0x4D) return true; // BMP
    return false;
  }
}
